// SPDX-FileCopyrightText: 2023-2025 Sangfor Technologies Inc.
// SPDX-License-Identifier: Mulan PSL v2
package storage

import (
	"math"
	"time"

	"gorm.io/gorm"

	"code.geniusai.org/notebook-manager/pkg/entity"
)

type NotebookStoreInterface interface {
	CreateNotebook(*gorm.DB, *entity.Notebook) (*entity.Notebook, error)
	GetNotebook(id string) (*entity.Notebook, error)
	DeleteNotebook(id string) error
	DeleteNotebookRecords(db *gorm.DB, userId string) error
	GetNotebookByProjectId(db *gorm.DB, projectId string) ([]*entity.Notebook, error)
	UpdateNotebook(string, *entity.ModifyNotebook) error
	UpdateNotebookActive(id string) error
	GetInactiveExpire(int64) ([]*entity.Notebook, error)
	ListNotebook(opts *entity.ProjectListOption) (int, []*entity.Notebook, error)
}

type NotebookStore struct {
	db *gorm.DB
}

func NewNotebookStore(db *gorm.DB) NotebookStoreInterface {
	return &NotebookStore{db}
}

func (m *NotebookStore) CreateNotebook(db *gorm.DB, notebook *entity.Notebook) (*entity.Notebook, error) {
	result := db.Create(notebook)
	return notebook, result.Error
}

func (m *NotebookStore) GetNotebook(id string) (*entity.Notebook, error) {
	notebook := &entity.Notebook{ID: id}
	result := m.db.First(notebook)
	return notebook, result.Error
}

func (m *NotebookStore) DeleteNotebook(id string) error {
	notebook := &entity.Notebook{ID: id}
	result := m.db.Delete(notebook)
	return result.Error
}

func (m *NotebookStore) DeleteNotebookRecords(db *gorm.DB, userId string) error {
	return db.Where("user_id = ?", userId).
		Delete(&entity.Notebook{}).Error
}

func (m *NotebookStore) UpdateNotebook(id string, modifyNotebook *entity.ModifyNotebook) error {
	updateData := map[string]interface{}{
		"description":       modifyNotebook.Description,
		"image":             modifyNotebook.Image,
		"cpu_num":           modifyNotebook.CpuNum,
		"gpu_num":           modifyNotebook.GpuNum,
		"gpu_name":          modifyNotebook.GpuName,
		"vgpu_num":          modifyNotebook.VGpuNum,
		"vgpu_memory":       modifyNotebook.VGpuMemory,
		"is_vgpu":           modifyNotebook.IsVGpu,
		"memory_size":       modifyNotebook.MemorySize,
		"vgpu_display_name": modifyNotebook.VGpuDisplayName,
	}
	err := m.db.Model(&entity.Notebook{}).
		Where("id = ?", id).
		Updates(updateData).
		Error
	return err
}

func (m *NotebookStore) UpdateNotebookActive(id string) error {
	timestamp := int(time.Now().Unix())
	err := m.db.Model(&entity.Notebook{}).
		Where("id = ?", id).
		Update("last_active", timestamp).
		Error
	return err
}

func (m *NotebookStore) GetInactiveExpire(expireTime int64) ([]*entity.Notebook, error) {
	notebooks := make([]*entity.Notebook, 0)
	err := m.db.Where("last_active < ?", expireTime).
		Find(&notebooks).
		Error
	return notebooks, err
}

func (m *NotebookStore) GetNotebookByProjectId(db *gorm.DB, projectId string) ([]*entity.Notebook, error) {
	list := make([]*entity.Notebook, 0)
	err := m.db.Transaction(func(tx *gorm.DB) error {
		query := tx.Model(entity.Notebook{}).
			Where("project_id = ?", projectId)
		e := query.Find(&list).Error
		if e != nil {
			return e
		}
		return nil
	})
	if err != nil {
		return nil, err
	}
	return list, err
}

func (m *NotebookStore) ListNotebook(option *entity.ProjectListOption) (int, []*entity.Notebook, error) {
	// 过滤关键字, 排序, 分页
	if option.PageSize == 0 {
		option.PageNum = 0
		option.PageSize = math.MaxInt8
	}
	keyword, err := ProcessKeyword(option.Keyword)
	if err != nil {
		return 0, nil, err
	}

	var total int
	pageList := make([]*entity.Notebook, 0)
	err = m.db.Transaction(func(tx *gorm.DB) error {
		query := tx.Model(entity.Notebook{}).
			//Where("user_id = ? and project_id = ?", option.UserID, option.ProjectID)
			// 去掉根据项目过滤
			Where("user_id = ?", option.UserID)
		if option.Keyword != "" {
			query = query.Where("name like ?", keyword)
		}
		var total64 int64
		qErr := query.Count(&total64).Error
		if qErr != nil {
			return qErr
		}
		total = int(total64)
		start := option.PageSize * option.PageNum
		if start < total {
			end := option.PageSize*option.PageNum + option.PageSize
			limit := option.PageSize
			if end >= total {
				limit = end - start
			}
			qErr := query.Order("update_time desc").
				Offset(start).
				Limit(limit).
				Find(&pageList).Error
			if qErr != nil {
				return qErr
			}
		}
		return nil
	})
	if err != nil {
		return 0, nil, err
	}

	return total, pageList, nil
}
